/*
 * File:   thread.c
 * Author: Kevin Ouwens
 *
 * Version: 0.5
 *
 * Created on January 17, 2010, 12:56 PM
 *
 * Info:
 * This is the code that all connected users will be using, with their structs
 * to make sure they don't interfere with eachother.
 * This works in combination with clientcmd.c, download.c and upload.c
 *
 */

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <strings.h>
#include "hfile.h"

void *mainThread(void *clientNo);

int createClientThread(int clientNo)
{
    pthread_t threadID;
    printf("creating thread for clientNo: %d\n", clientNo);
    //put the client in a thread.
    pthread_create(&threadID, NULL, mainThread, (void *)clientNo);
    return 0;
}
//we still need to determine how to place clients more effeciently
clientInfo client[50];
void *mainThread(void *clientNumber)
{
    printf("entered mainThread\n");
    //variables used by client after connecting
    //this does need to be mutexed?
    int clientNo = (int)clientNumber;
    char cCFDFull[10], cCFDEmpty[10], cCFDSem[10];
    char *cFull;
    char *cEmpty;
    char cMemFullPath[1000];
    char *cMemFilePath = {"/tmp/"};
    char *cMemExtention = {".bin"};
    char *defaultDir = {"./files/"};
    //end of variables
    client[clientNo].clientNo = clientNo;
    client[clientNo].cCurrentDir = defaultDir;

    //get semephore names and open semaphores for the client
    sprintf(cCFDFull,"%d",clientNo);
    cFull = strcat((char*) cCFDFull, "Full");
    sprintf(cCFDEmpty,"%d",clientNo);
    cEmpty = strcat((char*) cCFDEmpty, "Empty");
    printf("semaphore names passed\n");
    printf("cFull: %s\n", cFull);
    printf("cEmpty: %s\n", cEmpty);

    if((client[clientNo].semaphoreFull = sem_open(cFull, 0))== SEM_FAILED)
    {
        perror("open semFull: ");
        if(sem_unlink(cFull) <0)
        {
            perror("Unlink at semFull");
        }
    }

    if((client[clientNo].semaphoreEmpty = sem_open(cEmpty, 0))== SEM_FAILED)
    {
        perror("open semEmpty: ");
        if(sem_unlink(cEmpty) <0)
        {
            perror("Unlink at semEmpty");
        }
    }
    printf("opened semaphores for client\n");
    //end of opening semafores

    //preperation for opening the mmap
    strcat(cMemFullPath, cMemFilePath);
    sprintf(cCFDSem,"%d",clientNo);
    strcat(cMemFullPath, cCFDSem);
    strcat(cMemFullPath, cMemExtention);
    client[clientNo].cMemMapPath = cMemFullPath;
    printf("cMemFullPath: %s\n", client[clientNo].cMemMapPath);//Debug
    //end of preperation mmap
    printf("cMemMapPath: %s\n", client[clientNo].cMemMapPath);
    //open the mmap for reading and writing
    if((client[clientNo].iMapFd = open(client[clientNo].cMemMapPath, O_RDWR, ACC_RIGHT))<0)
    {
        perror("error opening mapFd\n");
        exit(EXIT_FAILURE);
    }
    printf("imapfd after opening it: %d\n", client[clientNo].iMapFd);
    printf("clientNo BEFORE map: %d\n", clientNo);

    if((client[clientNo].cMapFile = mmap(0, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, client[clientNo].iMapFd, 0))== MAP_FAILED) //< i forgot PROT_WRITE... seriously...
    {
        close(client[clientNo].iMapFd);
        perror("Error mmapping the file");
        exit(EXIT_FAILURE);
    }
    printf("AFTER mapped complete\n");
    //end of opening.

    //notify CHP
    if((sem_post(client[clientNo].semaphoreEmpty))<0)
    {
        perror("sem_post semaphores[clientNo]");
    }
    printf("semaphoreEmpty posted\n");

    //infinite loop which the client will stay in forever.
    while(1)
    {
        lseek(client[clientNo].iMapFd, 0, SEEK_SET);
        printf("while loop entered\n");
        //wait for a notice from CHP
        if((sem_wait(client[clientNo].semaphoreFull))<0)
        {
            perror("sem_wait semfull clientno");
        }
        printf("wait for semFull[clientNo] complete\n");
        //read the data posted by CHP in the mmap
        read(client[clientNo].iMapFd, client[clientNo].tempBuff, CHUNKSIZE);

        printf("inhoud map: %s\n", client[clientNo].tempBuff);
        //analyze the data with clientCmd.
        clientCmd(client[clientNo].clientNo, client);
    }
}